/**********************************************************************
 * sht30.c
 *Copyright:(C)ZhouYanlin<www.zhouyanlin1222@qq.com>
 *
 *Description:  Common AT command source code
 *
 *
 *  Created on: 2021年5月30日
 *      Author: ZhouYanlin
 **********************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "at_cmd.h"

#define	ATCMD_REPLY_LEN		256

/* AT_CMD 调试宏,注释下面两个宏定义可以取消调试打印 */
//#define CONFIG_AT_CMD_DEBUG
//#define CONFIG_AT_CMD_PRINT

#ifdef CONFIG_AT_CMD_DEBUG
#define at_dbg(format,args...) printf(format, ##args)
#else
#define at_dbg(format,args...) do{} while(0)
#endif

#ifdef CONFIG_AT_CMD_PRINT
#define at_printf(format,args...) printf(format, ##args)
#else
#define at_printf(format,args...) do{} while(0)
#endif

/* Send AT command */
int send_atcmd(char *atcmd, char *expect_reply, unsigned int timeout, char *outbuf, int size_outbuf)
{
	int                       rv = -3;
	unsigned int              i;
	char                     *expect;

	/* check function input arguments validation */
	if(  NULL == atcmd || strlen(atcmd)<=0 )
	{
		at_printf("%s-->ERROR: Invalid input arguments\r\n", __FUNCTION__);
		return -1;
	}

	at_dbg("\r\nStart send AT command: %s", atcmd);
	clear_atcmd_rxbuf();
	HAL_UART_Transmit(at_uart, (uint8_t *)atcmd, strlen(atcmd), 1000);

	expect = expect_reply ? expect_reply : "OK\r\n";

	/* Receive AT reply string by UART interrupt handler, stop by "OK/ERROR" or timeout */
	for(i=0; i<timeout; i++)
	{
		if( strstr(g_atcmd_rxbuf, expect) )
		{
			at_printf("AT command Got expect reply '%s'\r\n", expect);
			rv = 0;
			goto CleanUp;
		}

		if( strstr(g_atcmd_rxbuf, "ERROR\r\n") || strstr(g_atcmd_rxbuf, "FAIL\r\n"))
		{
			rv = -2;
			goto CleanUp;
		}

		HAL_Delay(1);
	}


CleanUp:
	if( outbuf && size_outbuf>0 )
	{
		strncpy(outbuf, g_atcmd_rxbuf, size_outbuf);
	}
	at_dbg("<<<< AT command reply:\r\n%s", g_atcmd_rxbuf);
	return rv;
}


/* Description: Send AT command which will only reply by "OK" or "ERROR", such as AT+RST:
 * Reply:   \r\nREBOOT_CAUSE_SECURITY_PMU_POWER_ON_RESET\r\nNeul\r\nOK\r\n
 * Return Value: 0: OK     -X: Failure
 *
 */
int send_atcmd_check_str(char *atcmd, char *expect_reply, unsigned int timeout)
{
    if( NULL == atcmd || NULL ==expect_reply)
    {
    	at_printf("%s--->Invalid input arguments\r\n",__FUNCTION__);
        return -1;
    }

	return send_atcmd(atcmd, expect_reply, timeout, NULL, 0);
}


/* Send atcmd and check OK
 *
 *  Description: Send AT command which will only reply by "OK" or "ERROR", such as AT:
 *                 Reply:   \r\nOK\r\n
 * Return Value: 0: OK     -X: Failure
 */
int send_atcmd_check_ok(char *atcmd, unsigned int timeout)
{
    if( NULL == atcmd )
    {
    	at_printf("%s--->Invalid input arguments\r\n",__FUNCTION__);
        return -1;
    }

    return send_atcmd(atcmd, NULL, timeout, NULL, 0);
}


/*
 *  Description: Send AT command which will reply by a value directly in a single line, such as AT+CGMM:(生产厂商的标识)
 *                  Reply:   \r\nEC20F\r\nOK\r\n
 *
 * Return Value: 0: OK     -X: Failure
 */
int send_atcmd_check_value(char *atcmd, unsigned int timeout, char *reply, int size_reply)
{
    int                     i = 0;
    int                     rv;
    char                    buf[ATCMD_REPLY_LEN];
    char                   *ptr_start, *ptr_end;

    if( !atcmd || !reply || size_reply<=0 )
    {
    	at_printf("%s--->Invalid input arguments\r\n", __FUNCTION__);
        return -1;
    }

    /*send AT command*/
    rv = send_atcmd(atcmd, NULL, timeout, buf, sizeof(buf));
    if( rv < 0 )
    {
        return -2;
    }

    /*Find start position */
    ptr_start=strchr(buf, '\n'); /* found '\n' before the value */
    if( !ptr_start )
    {
        return -3;
    }
    ptr_start++;   /* skip '\n' */

    /*Find end position */
    ptr_end=strstr(buf, "\r\n\r\nOK\r\n");
    if( !ptr_end )
    {
        return -3;
    }

    /*copy reply out */
    memset(reply, 0, size_reply);
    while(ptr_start<ptr_end && i<size_reply)
    {
        reply[i++] = *ptr_start;
        ptr_start ++;
    }

    return 0;
}


/*
 *  Description: Send AT command which will reply by the value  with a prefix "+CMD: " line, such as AT+CSQ:
 *  Reply:   \r\n+CSQ: 26,99\r\nOK\r\n
 *
 * Return Value: 0: OK     -X: Failure
 */
int send_atcmd_check_request(char *atcmd, unsigned int timeout, char *reply, int size_reply)
{
    int                     i = 0;
    int                     rv;
    char                    buf[ATCMD_REPLY_LEN];
    char                   *ptr_start, *ptr_end;

    if( NULL == atcmd || NULL == reply || size_reply<=0 )
    {
    	at_printf("%s--->Invalid input arguments\r\n",__FUNCTION__);
        return -1;
    }

    /*send AT command */
    rv = send_atcmd(atcmd, NULL, timeout, buf, sizeof(buf));
    if( rv < 0 )
    {
    	at_printf("send_atcmd failure, rv=%d\r\n", rv);
        return -2;
    }

    /*Find start position */
#if 0
    ptr_start=strchr(buf, '+');  /* found '+' before the value */
    if( !ptr_start )
    {
        return -3;
    }
    ptr_start++;   /* skip '+'  */
#endif
    ptr_start=strchr(buf, ':');  /* found ':' before the value */
    if( !ptr_start )
    {
        return -4;
    }
    ptr_start++;   /* skip ':'  */

    /*Find end position */
    ptr_end=strstr(buf, "\r\nOK\r\n");
    if( !ptr_end )
    {
        return -5;
    }

    if( *(ptr_end-1) == '\n' )
    {
    	ptr_end -= 2; /* remove previous \r\n */
    }

    /*copy reply out*/
    memset(reply, 0, size_reply);
    while(ptr_start<ptr_end && i<size_reply)
    {
        reply[i++] = *ptr_start;
        ptr_start ++;
    }

    return 0;
}

/* 函数说明： 给模块发送"AT"命令，确认模块是否正常回复。
 * 输入参数： $times: 尝试发送 AT 命令测试的次数
 *  返回值： 0: 发送AT命令收到OK回复     <0: 发送AT命令等待回复失败。
 */
int send_atcmd_check_module(void)
{
	int			rv = -3;

		rv = send_atcmd_check_ok("AT\r", 500);
		if(-1 == rv)
		{
			at_printf("%s--->Invalid input arguments\r\n",__FUNCTION__);
			return -1;
		}

		if( !rv )
		{
			at_printf("INFO: Send 'AT' to BC28 NB-IoT module and got reply ok\r\n");
			return 0;
		}

		HAL_Delay(100);

	return -1;
}


/* 函数说明： 给模块发送"ATE0"关闭回显，或 "ATE1" 打开回显。
 * 输入参数： $on: 打开还是关闭回显,ECHO_OFF 或  ECHO_ON
 *  返回值： 0: 发送成功     <0: 发送失败。
 */
int set_atcmd_echo(int status)
{
	int        mode = status ? 1 : 0;
	char       atcmd[64];

	snprintf(atcmd, sizeof(atcmd), "ATE%d\r\n", mode);

	if( !send_atcmd_check_ok(atcmd, 1000) )
	{
		at_printf("INFO: Send 'ATE%d' to BC28 NB-IoT module and got reply ok\r\n", mode);
		return 0;
	}

	return -1;
}

#if 0
int send_atcmd(char *atcmd, char *expect_reply, unsigned int timeout)
{
	int                       rv = 1;
	unsigned int              i;
	char                     *expect;

	/* check function input arguments validation */
	if(  !atcmd || strlen(atcmd)<=0 )
	{
		printf("ERROR: Invalid input arguments\r\n");
		return -1;
	}

	at_dbg("\r\nStart send AT command: %s", atcmd);
	clear_atcmd_rxbuf();
	HAL_UART_Transmit(at_uart, (uint8_t *)atcmd, strlen(atcmd), timeout);

	expect = expect_reply ? expect_reply : "OK";

	/* Receive AT reply string by UART interrupt handler, stop by "OK/ERROR" or timeout */
	for(i=0; i<timeout; i++)
	{
		if( strstr(g_atcmd_rxbuf, expect) )
		{
			at_dbg("AT command Got expect reply '%s'\r\n", expect);
			rv = 0;
			goto CleanUp;
		}

		if( strstr(g_atcmd_rxbuf, "ERROR"))
		{
			rv = 1;
			goto CleanUp;
		}

		HAL_Delay(1);
	}

	rv = 2;

CleanUp:
	at_dbg("<<<< AT command reply:%s\r\n", g_atcmd_rxbuf);
	return rv;
}

#endif

